/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
/* eslint-disable no-shadow */
/* eslint-disable no-use-before-define */
import { computed, ref } from 'vue';
import type { SetupContext } from 'vue';
import {
  CalendarWeekEmits,
  CalendarWeekProps,
  IEvent,
  IUIEvent,
  IUILegend,
} from '../interface';
import {
  fade,
  getCurWeekDates,
  handleBkColor,
  handleEVentClick,
  handleTimeRange,
  isDateInCurWeek,
  isTimeGreaterThan,
  isToday,
} from '../util';

export const useCalendarWeek = (
  props: CalendarWeekProps,
  emit: SetupContext<CalendarWeekEmits>['emit'],
) => {
  const drawData = ref<string[]>([]);
  const curTimeTimer = ref();
  const curTimeTop = ref(1);
  const curTimeVal = ref('00:00');
  const resizableHand = ref();
  const calendarWeek = ref();
  const legends = ref();
  const multiple = computed(() => props.multiple === true);
  const selectedData = ref<IEvent[]>([]);
  const rows = ref<IData[]>([]);
  const rowsHeader = ref<IData[]>([]);
  const weekDays = ref<IData>([]);
  const popVisible = ref(true);

  // 记录初始鼠标位置和要改变大小的元素的初始大小
  let initialMouseY = 0;
  let initialHeight = 0;
  /**
   * @description 开始拖动，初始化节点数据
   * @param {DragEvent} event
   */
  const handleDragStart = (event: DragEvent) => {
    initialMouseY = (event as IParams).clientY;
    initialHeight = parseInt(
      window.getComputedStyle(resizableHand.value).height,
      10,
    );
  };

  /**
   * @description 处理拖动
   * @param {DragEvent} event
   */
  const handleDrag = (event: DragEvent) => {
    const heightChange: number =
      (event as IParams).clientY - initialMouseY + initialHeight;
    resizableHand.value.style.height = `${heightChange}px`;
  };

  /**
   * @description 获取两个时间范围内的所有时间
   * @
   */
  const getDateRanges = (firstDate: Date | string, lastDate: Date | string) => {
    const firstDay = new Date(firstDate);
    const targetDate = new Date(lastDate);
    const dateArray = [];
    firstDay.setHours(0, 0, 0, 0);
    targetDate.setHours(0, 0, 0, 0);
    // 循环从开始时间到目标日期，将中间日期添加到数组中
    for (
      let currentDate = new Date(firstDay);
      currentDate <= targetDate;
      currentDate.setDate(currentDate.getDate() + 1)
    ) {
      dateArray.push(new Date(currentDate));
    }
    return dateArray;
  };

  /**
   * @description 计算events数据
   */
  const handleUIEvents = () => {
    const events = props.events;
    const curDate = props?.selectedDay;
    const tempColors = new Map();
    const { firstDay, lastDay } = getCurWeekDates(curDate);
    // 初始化二维数组数据
    const tempArray: IData = [];
    const tempEvents: IData[] = [];
    const tempRowsHeader: IData[] = [];
    weekDays.value = [];
    for (let i = 0; i < 7; i++) {
      const addDay = i;
      const dayValue = firstDay.getDate() + addDay;
      const date = new Date(
        firstDay.getFullYear(),
        firstDay.getMonth(),
        dayValue,
      );
      const day = date.getDate();
      const tempWeeks = [
        'sunday',
        'monday',
        'tuesday',
        'wednesday',
        'thursday',
        'friday',
        'saturday',
      ];
      const weeks = tempWeeks.map((item: string) => {
        return ibiz.i18n.t(`control.calendar.calendarweek.weeks.${item}`);
      });
      const caption = weeks[i];
      const isActivate = isToday(date, curDate);
      const item = { date, day, caption, isActivate };
      weekDays.value.push(item);
      tempArray.push([]);
      tempEvents.push([]);
      tempRowsHeader.push([]);
    }
    // 根据事件数据分类并计算ui绘制数据
    events.forEach((event: IUIEvent) => {
      if (event.beginTime) {
        const item = {} as IUIEvent;
        Object.assign(item, event);
        const targetEvent = selectedData.value.find(
          (tempItem: IUIEvent) => tempItem.id === event.id,
        );
        // 判断事件是否默认选中
        if (targetEvent) {
          Object.assign(item, { isSelectedEvent: true });
        } else {
          Object.assign(item, { isSelectedEvent: false });
        }
        // 如果没有结束时间，默认赋值开始时间
        if (!event.endTime && event.beginTime) {
          Object.assign(item, { endTime: event.beginTime });
        }
        // 过滤，通过判断开始或结束时间是否在当前周范围内
        if (
          isDateInCurWeek(item.beginTime, firstDay, lastDay) &&
          isDateInCurWeek(item.endTime, firstDay, lastDay)
        ) {
          const dateArray: Date[] = getDateRanges(item.beginTime, item.endTime);
          dateArray.forEach((date: Date) => {
            const weekIndex = new Date(date).getDay();
            tempArray[weekIndex].push(item);
          });
        } else if (
          isDateInCurWeek(item.beginTime, firstDay, lastDay) &&
          !isDateInCurWeek(item.endTime, firstDay, lastDay)
        ) {
          const dateArray: Date[] = getDateRanges(item.beginTime, lastDay);
          dateArray.forEach((date: Date) => {
            const weekIndex = new Date(date).getDay();
            tempArray[weekIndex].push(item);
          });
        } else if (
          isDateInCurWeek(item.endTime, firstDay, lastDay) &&
          !isDateInCurWeek(item.beginTime, firstDay, lastDay)
        ) {
          const dateArray: Date[] = getDateRanges(firstDay, item.endTime);
          dateArray.forEach((date: Date) => {
            const weekIndex = new Date(date).getDay();
            tempArray[weekIndex].push(item);
          });
        } else if (
          !isDateInCurWeek(event.endTime, firstDay, lastDay) &&
          !isDateInCurWeek(event.beginTime, firstDay, lastDay) &&
          isTimeGreaterThan(firstDay, event.beginTime) &&
          isTimeGreaterThan(event.endTime, firstDay)
        ) {
          const dateArray: Date[] = getDateRanges(firstDay, lastDay);
          dateArray.forEach((date: Date) => {
            const weekIndex = new Date(date).getDay();
            tempArray[weekIndex].push(item);
          });
        }
      }
    });
    // 排序
    tempArray.forEach((item: IData) => {
      item.sort((a: IParams, b: IParams) => {
        const tempA = a;
        const tempB = b;
        const beginTimeDifference =
          new Date(tempA.beginTime).getTime() -
          new Date(tempB.beginTime).getTime();
        let type;
        if (beginTimeDifference === 0) {
          type =
            new Date(tempA.endTime).getTime() -
            new Date(tempB.endTime).getTime();
        } else {
          type = beginTimeDifference;
        }
        return type;
      });
    });
    // 初始化ui参数
    tempArray.forEach((item: IData, hostIndex: number) => {
      item.forEach((event: IData, index: number) => {
        const targetLegend = legends.value.find((legendItem: IUILegend) =>
          Object.is(legendItem.id, event.itemType),
        );
        // 图例过滤
        if ((targetLegend && targetLegend.isShow) || !targetLegend) {
          const tempEventContent = {} as IUIEvent;
          const tempEventHeader = {};
          const length = tempArray[hostIndex].length;
          const weekDay: IParams = weekDays.value[hostIndex];

          // 处理内容区的ui绘制数据
          Object.assign(tempEventContent, event);
          Object.assign(tempEventContent, { zIndex: index + 1 });
          // 计算宽度
          const percentage: number = Number((100 / length).toFixed(3));
          const width = `${percentage}%`;
          // 计算定位
          const styleLeft = `${index * percentage}%`;
          Object.assign(tempEventContent, { width, styleLeft });
          // 计算高度定位及显示时间范围
          let height = 3;
          let styleTop = 60;
          let timeRange = '';
          if (isToday(event.beginTime, event.endTime)) {
            height = getEventHeight(event.beginTime, event.endTime);
            timeRange = handleTimeRange(
              event.beginTime,
              event.endTime,
              'HH:mm',
            );
            const tempVal = handleTopOrCurVal(new Date(event.beginTime));
            styleTop = tempVal.styleTop;
          } else if (
            isToday(event.beginTime, weekDay.date) &&
            !isToday(event.endTime, weekDay.date)
          ) {
            const endDate = new Date(weekDay.date);
            endDate.setHours(23, 59, 59, 0);
            height = getEventHeight(event.beginTime, endDate);
            timeRange = handleTimeRange(
              event.beginTime,
              event.endTime,
              'YYYY-MM-DD HH:mm',
            );
            const tempVal = handleTopOrCurVal(new Date(event.beginTime));
            styleTop = tempVal.styleTop;
          } else if (
            isToday(event.endTime, weekDay.date) &&
            !isToday(event.beginTime, weekDay.date)
          ) {
            const beginDate = new Date(weekDay.date);
            beginDate.setHours(0, 0, 0, 0);
            height = getEventHeight(beginDate, event.endTime);
            timeRange = handleTimeRange(
              event.beginTime,
              event.endTime,
              'YYYY-MM-DD HH:mm',
            );
            const tempVal = handleTopOrCurVal(new Date(beginDate));
            styleTop = tempVal.styleTop;
          } else {
            const date = new Date(weekDay.date);
            const beginDate = new Date(date.setHours(0, 0, 0, 0));
            const endDate = new Date(date.setHours(23, 59, 59, 59));
            height = getEventHeight(beginDate, endDate);
            timeRange = handleTimeRange(
              event.beginTime,
              event.endTime,
              'YYYY-MM-DD HH:mm',
            );
            const tempVal = handleTopOrCurVal(new Date(beginDate));
            styleTop = tempVal.styleTop;
          }
          Object.assign(tempEventContent, { height, styleTop, timeRange });
          if (!event?.bkColor) {
            const bkColor = targetLegend
              ? targetLegend.bkcolor
              : handleBkColor(tempColors, event.itemType);
            Object.assign(tempEventContent, { bkColor });
          }
          if (tempEventContent.bkColor) {
            const tempBkColor = fade(tempEventContent.bkColor, 10);
            Object.assign(tempEventContent, {
              bkColorFade: tempBkColor,
            });
          }
          // 计算边框显示
          if (
            tempEventContent?.height &&
            (tempEventContent as IParams)?.height > 10
          ) {
            const border = '1px solid #FFF';
            Object.assign(tempEventContent, { border });
          } else {
            Object.assign(tempEventContent, { border: 'none' });
          }
          tempEvents[hostIndex].push(tempEventContent as IEvent);

          // 处理头部ui绘制的数据
          // 过滤开始与结束时间在同一天
          if (!isToday(event.beginTime, event.endTime)) {
            Object.assign(tempEventHeader, tempEventContent);
            Object.assign(tempEventHeader, {
              width: 0,
              styleLeft: 0,
            });
            // 计算宽度及left定位
            let headerEVentWidth: number | string = 0;
            let headerEventLeft: number | string = 0;
            if (
              isDateInCurWeek(event.beginTime, firstDay, lastDay) &&
              isDateInCurWeek(event.endTime, firstDay, lastDay)
            ) {
              const eventWidth = handleHeaderEventWidth(
                event.beginTime,
                event.endTime,
                firstDay,
                lastDay,
              );
              const eventLeft = handleHeaderEventLeft(
                event.beginTime,
                firstDay,
                lastDay,
              );
              headerEVentWidth = `${eventWidth}%`;
              headerEventLeft = `${eventLeft}%`;
            } else if (
              isDateInCurWeek(event.beginTime, firstDay, lastDay) &&
              !isDateInCurWeek(event.endTime, firstDay, lastDay)
            ) {
              const eventWidth = handleHeaderEventWidth(
                event.beginTime,
                lastDay,
                firstDay,
                lastDay,
              );
              const eventLeft = handleHeaderEventLeft(
                event.beginTime,
                firstDay,
                lastDay,
              );
              headerEVentWidth = `${eventWidth}%`;
              headerEventLeft = `${eventLeft}%`;
            } else if (
              isDateInCurWeek(event.endTime, firstDay, lastDay) &&
              !isDateInCurWeek(event.beginTime, firstDay, lastDay)
            ) {
              const eventWidth = handleHeaderEventWidth(
                firstDay,
                event.endTime,
                firstDay,
                lastDay,
              );
              headerEVentWidth = `${eventWidth}%`;
              headerEventLeft = `${0}%`;
            } else if (
              !isDateInCurWeek(event.endTime, firstDay, lastDay) &&
              !isDateInCurWeek(event.beginTime, firstDay, lastDay) &&
              isTimeGreaterThan(firstDay, event.beginTime) &&
              isTimeGreaterThan(event.endTime, firstDay)
            ) {
              const eventWidth = handleHeaderEventWidth(
                firstDay,
                lastDay,
                firstDay,
                lastDay,
              );
              headerEVentWidth = `${eventWidth}%`;
              headerEventLeft = `${0}%`;
            }
            Object.assign(tempEventHeader, {
              width: headerEVentWidth,
              styleLeft: headerEventLeft,
            });
            // 判断事件开始时间是否在当前周，或者当前周为0时才显示
            let eventHeaderIsShow = false;
            if (
              isDateInCurWeek(event.beginTime, firstDay, lastDay) &&
              isToday(event.beginTime, weekDay.date)
            ) {
              eventHeaderIsShow = true;
            } else if (hostIndex === 0) {
              eventHeaderIsShow = true;
            }
            Object.assign(tempEventHeader, {
              isShow: eventHeaderIsShow,
            });

            tempRowsHeader[hostIndex].push(tempEventHeader);
          }
        }
      });
    });
    tempColors.clear();
    rows.value = tempEvents as IData[];
    rowsHeader.value = tempRowsHeader as IData[];
  };

  /**
   * @description 获取事件卡片展示高度
   * @param {string | Date} startTime
   * @param {string | Date} endTime
   * @returns {number}
   */
  const getEventHeight = (startTime: string | Date, endTime: string | Date) => {
    let height = 1;
    if (isToday(startTime, endTime)) {
      const difference =
        new Date(endTime).getTime() - new Date(startTime).getTime();
      height = Math.floor(difference / (1000 * 60));
    }
    if (height < 3) {
      height = 3;
    }
    return height;
  };

  /**
   * @description 获取头部事件卡片展示宽度
   * @param {string | Date} startTime
   * @param {string | Date} endTime
   * @returns {number}
   */
  const handleHeaderEventWidth = (
    startTime: string | Date,
    endTime: string | Date,
    firstDay: string | Date,
    lastDay: string | Date,
  ) => {
    let eventWidth = '0';
    if (
      isDateInCurWeek(startTime, firstDay, lastDay) &&
      isDateInCurWeek(endTime, firstDay, lastDay)
    ) {
      const hour = 24;
      const ratio = Number((100 / hour).toFixed(3));
      const difference =
        new Date(endTime).getTime() - new Date(startTime).getTime();
      const totalHours = difference / (1000 * 60 * 60);
      eventWidth = (totalHours * ratio).toFixed(3);
    }
    return eventWidth;
  };

  /**
   * @description 获取头部事件卡片展示left定位
   * @param {string | Date} startTime
   * @param {string | Date} endTime
   * @returns {number}
   */
  const handleHeaderEventLeft = (
    startTime: string | Date,
    firstDay: string | Date,
    lastDay: string | Date,
  ) => {
    let eventLeft = '0';
    if (isDateInCurWeek(startTime, firstDay, lastDay)) {
      const beginTimeHour = new Date(startTime).getHours();
      const beginTimeMinutes = new Date(startTime).getMinutes() / 60;
      const hour = 24;
      const ratio = Number((100 / hour).toFixed(3));
      const positionTotalHour = beginTimeHour + beginTimeMinutes;
      eventLeft = (positionTotalHour * ratio).toFixed(3);
    }
    return eventLeft;
  };

  /**
   * @description 处理定位高度及当前时间显示值
   * @param {Date} date
   * @returns {{number, string}} {styleTop, timeVal}
   */
  const handleTopOrCurVal = (date: Date) => {
    const currentHours = date.getHours();
    const currentMinutes = date.getMinutes();
    const hours = String(currentHours).padStart(2, '0');
    const minutes = String(currentMinutes).padStart(2, '0');
    let styleTop;
    let timeVal;
    if (currentHours === 0 && currentMinutes === 0) {
      styleTop = 1;
      timeVal = '00:00';
    } else {
      const topVal = currentHours * 60 + currentMinutes;
      styleTop = topVal;
      timeVal = `${hours}:${minutes}`;
    }
    return { styleTop, timeVal };
  };

  /**
   * @description 处理当前时间显示内容及定位高度
   */
  const handleCurTime = () => {
    const { styleTop, timeVal } = handleTopOrCurVal(new Date());
    curTimeTop.value = styleTop;
    curTimeVal.value = timeVal;
  };

  /**
   * @description 初始化数据
   * @returns {string[]}
   */
  const initDrawData = () => {
    const tempDrawData = [];
    for (let i = 1; i < 24; i++) {
      const hours = String(i).padStart(2, '0');
      const timescale = `${hours}:00`;
      tempDrawData.push(timescale);
    }
    return tempDrawData;
  };

  /**
   * @description 事件点击
   * @param {IUIEvent} item
   * @param {string} location
   */
  const eventClick = async (item: IUIEvent, location: string) => {
    popVisible.value = false;
    const res = await handleEVentClick(
      item,
      location,
      props.events,
      multiple.value,
      selectedData.value,
      emit,
    );
    const { tempSelectedData, isSelectedEvent } = res as IParams;
    if (!isSelectedEvent) {
      Object.assign(item, { isSelectedEvent });
    }
    selectedData.value = tempSelectedData;
    handleUIEvents();
  };

  return {
    drawData,
    curTimeTimer,
    curTimeTop,
    curTimeVal,
    rows,
    resizableHand,
    calendarWeek,
    selectedData,
    weekDays,
    legends,
    rowsHeader,
    popVisible,
    handleCurTime,
    handleDrag,
    handleDragStart,
    eventClick,
    initDrawData,
    handleUIEvents,
  };
};
